/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - core/math/vector
// Copyright (c) 2014.  All Rights Reserved
//
// File:		AESimdFloat32.h
// Author:		Gianluca Belardelli
// Date:		10/01/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AESIMDFLOAT32_H_
#define _AESIMDFLOAT32_H_

#ifndef _AEMATH_H_
	#error Attenzione. Includere il file core/math/AEMath.h invece di questo.
#endif

// Controllo degli errori durante la compilazione
namespace AECompileError
{
	template <bool b> struct AE_SIMDFLOAT_TEMPLATE_CONFIGURATION_NOT_IMPLEMENTED;
	template <> struct AE_SIMDFLOAT_TEMPLATE_CONFIGURATION_NOT_IMPLEMENTED<true>{ };

	template <bool b> struct AE_SIMDFLOAT_ILLEGAL_DIMENSION_USED;
	template <> struct AE_SIMDFLOAT_ILLEGAL_DIMENSION_USED<true>{ };

	template <bool b> struct AE_SIMDFLOAT_ILLEGAL_CONSTANT_REQUEST;
	template <> struct AE_SIMDFLOAT_ILLEGAL_CONSTANT_REQUEST<true>{ };
}
#define AE_SIMDFLOAT_DIMENSION_CHECK AE_COMPILE_TIME_ASSERT( N==1, AE_SIMDFLOAT_ILLEGAL_DIMENSION_USED )
#define AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED AE_COMPILE_TIME_ASSERT( A<0, AE_SIMDFLOAT_TEMPLATE_CONFIGURATION_NOT_IMPLEMENTED )

/// \class AESimdFloat32
///
/// A scalar floating point value. It holds one floating point number according to the
/// definition of AEFLOAT32. There are optimized SIMD implementations
/// available for several platforms. They use platform specific data structures and
/// code to provide efficient processing. Thus to be portable, nothing should be assumed
/// about the internal layout of the floating point value storage.
///
/// The setFromFloat() and getReal() methods work on ordinary AEFLOAT32 values. For performance
/// reasons you should only use them when the value needs to be available in
/// an ordinary processor register, because on most
/// platforms this requires leaving the SIMD processing pipeline. Calculations on AESimdFloat32
/// are much more efficient and combine better with hkVector4f processing. For loading and
/// storing a AESimdFloat32 from/to memory use the appropriate load() and store() methods which
/// offer aligned access.
///
/// The comparison methods produce compare masks which are compatible with hkVector4f
/// processing. For example, the selection between two hkVector4f can be based on the
/// mask produced by comparing two hkSimdReals.
///
/// Some floating point operations which involve division or square root calculations can be quite
/// slow. The implementation of this class offers improved performance for these operations
/// at the expense of accuracy and handling of denormalized floating point numbers. 
/// We have balanced performance with behavior one expects from a standard math operator,
/// but these methods will in general not behave IEEE compliant like the system math library
/// calls. See the comments on setDiv(), setReciprocal() and similar methods on how they behave.
///
/// If one needs to control the denormals handling, can do with even lower floating point
/// accuracy, or your algorithm requires full IEEE compliant behavior, the vector offers an 
/// advanced interface in the form of member template methods for the division and square
/// root routines. Each has explicit flags for controlling accuracy and denormal handling.
/// The given bit width is the calculated accuracy in the floating point mantissa.
/// The 23Bit versions are almost as precise as the full version (24Bit) but offer
/// a substantial speedup on most platforms because of less strict denorms handling. 
/// The 12Bit versions again offer faster execution with even less precision. Their 
/// usefulness depends on the algorithm at hand. When writing new code, it is 
/// recommended to start with the full precision version and then check whether a 
/// lower precision is acceptable. The template flags for controlling handling of
/// division-by-zero or negative square root arguments offer easy writing of checked
/// fail-safe math code.
///
/// The load() and store() methods do take a template parameter for interface compatibility with
/// hkVector4f. However the template parameter is checked at compile time to be 1.
/// The advanced interface in addition has template methods which take a flag for the
/// alignment of the memory pointer and for the rounding mode to apply in case of storing
/// to a lower precision floating point format.
///
/// \sa hkVector4f AEVector4fComparison hkHalf hkFloat16 hkMathAccuracyMode hkMathDivByZeroMode hkMathNegSqrtMode hkMathIoMode hkMathRoundingMode
class AE_COREDLLIMPEXP AESimdFloat32
{
// Members
public:
	/// Internal data storage for the floating point value (platform dependent).
	/// For writing portable code, nothing can be assumed about the internal layout of the value.
	AESingleFloat32 m_fReal;

// Methods
public:

	AE_DECLARE_NONVIRTUAL_CLASS_ALLOCATOR( TOBEDEFINED, AESimdFloat32 );

	///////////////////////////////////////////////////////////////
	/// @name Costruttori
	/// @{
	///////////////////////////////////////////////////////////////

	/// \brief
	/// Costruttore di default.<br>
	/// Crea un oggetto AESimdFloat32 senza inizializzarlo.
	AE_FORCEINLINE AESimdFloat32( void ) {}

	/// \brief
	/// Crea un nuovo oggetto AESimdFloat32 con il valore \a fValue.
	AE_FORCEINLINE AESimdFloat32( const AEFLOAT32 &fValue );

	///////////////////////////////////////////////////////////////
	/// @}
	/// @name Metodi statici di conversione
	/// @{
	///////////////////////////////////////////////////////////////
	
	/// \brief
	/// Crea un oggetto AESimdFloat32 con il valore \a fValue.
	/// \param fValue Valore da impostare.
	/// \return Ritorna un oggetto AESimdFloat32 con il valore convertito.
	AE_FORCEINLINE static const AESimdFloat32 AE_CALL Convert( const AESingleFloat32 &fValue );	

	/// \brief
	/// Metodo statico per creare un oggetto AESimdFloat32 da un valore AEFLOAT32.<BR>
	/// Il metodo evita se possibile l'overhead del costruttore.
	/// \param fValue Valore da impostare.
	/// \return Ritorna l'oggetto AESimdFloat32 inizializzato.
	AE_FORCEINLINE static AESimdFloat32 AE_CALL FromFloat( const AEFLOAT32 &fValue );

	/// \brief
	/// Metodo statico per creare un oggetto AESimdFloat32 da un valore AEUINT16.<BR>
	/// Il metodo evita se possibile l'overhead del costruttore.
	/// \param uiValue Valore da impostare.
	/// \return Ritorna l'oggetto AESimdFloat32 inizializzato.
	AE_FORCEINLINE static AESimdFloat32 AE_CALL FromUint16( const AEUINT16 &uiValue );

	/// \brief
	/// Metodo statico per creare un oggetto AESimdFloat32 da un valore AEUINT8.<BR>
	/// Il metodo evita se possibile l'overhead del costruttore.
	/// \param uiValue Valore da impostare.
	/// \return Ritorna l'oggetto AESimdFloat32 inizializzato.
	AE_FORCEINLINE static AESimdFloat32 AE_CALL FromUint8( const AEUINT8 &uiValue );

	/// \brief
	/// Metodo statico per creare un oggetto AESimdFloat32 da un valore AEINT32.<BR>
	/// Il metodo evita se possibile l'overhead del costruttore.
	/// \param nValue Valore da impostare.
	/// \return Ritorna l'oggetto AESimdFloat32 inizializzato.
	AE_FORCEINLINE static AESimdFloat32 AE_CALL FromInt32( const AEINT32 &nValue );

	/// \brief
	/// Ritorna il valore della costante indicata nel parametro del template.
	/// \sa AEVectorConstant
	template<int CONSTANT>
	AE_FORCEINLINE static const AESimdFloat32 AE_CALL GetConstant( void );
	
	/// \brief
	/// Ritorna il valore della costante indicata nel parametro \a vcConstant.
	/// \param vcConstant Indice della costante.
	/// \sa AEVectorConstant
	/// \remark Utilizzare questo metodo solo quando l'indice della costante non &egrave;
	/// conosciuto durante la compilazione.
	AE_FORCEINLINE static const AESimdFloat32 AE_CALL GetConstant( AEVectorConstant vcConstant );

	///////////////////////////////////////////////////////////////
	/// @}
	/// @name Inizializzazione
	/// @{
	///////////////////////////////////////////////////////////////
	
	/// \brief
	/// Imposta il valore di \c this con il valore di \a fValue.
	/// \param fValue Valore da impostare.
	AE_FORCEINLINE void SetFromFloat( const AEFLOAT32 &fValue );

	/// \brief
	/// Imposta il valore di \c this con il valore di \a dValue.
	/// \param dValue Valore da impostare.
	AE_FORCEINLINE void SetFromFloat( const AEDOUBLE64 &dValue );

	/// \brief
	/// Converte e imposta il valore di \c this con il valore di \a uiValue.
	/// \param uiValue Valore da impostare.
	AE_FORCEINLINE void SetFromUint16( const AEUINT16 &uiValue );

	/// \brief
	/// Converte e imposta il valore di \c this con il valore di \a uiValue.
	/// \param uiValue Valore da impostare.
	AE_FORCEINLINE void SetFromUint8( const AEUINT8 &uiValue );

	/// \brief
	/// Converte e imposta il valore di \c this con il valore di \a nValue.
	/// \param uiValue Valore da impostare.
	AE_FORCEINLINE void SetFromInt32( const AEINT32 &nValue );

	/// \brief
	/// Imposta il valore di \c this a 0.
	AE_FORCEINLINE void SetZero( void );

	/// \brief
	/// Ritorna se stesso come valore AEFLOAT32.
	AE_FORCEINLINE AEFLOAT32 GetReal( void ) const;

	/// \brief
	/// Converte il valore di se stesso in un intero e lo ritorna.<BR>
	/// L'intero &egrave; compreso nel range min/max del tipo di ritorno.
	/// \param *lpRes
	/// Puntatore nel quale il valore intero &egrave; convertito.
	AE_FORCEINLINE void StoreSaturateInt32( AEINT32 *lpRes ) const;

	/// \brief
	/// Converte il valore di se stesso in un intero e lo ritorna.<BR>
	/// L'intero &egrave; compreso nel range min/max del tipo di ritorno.
	/// \param *lpRes
	/// Puntatore nel quale il valore intero &egrave; convertito.
	AE_FORCEINLINE void StoreSaturateUint16( AEUINT16 *lpRes ) const;
	
	/// \brief
	/// Imposta se stesso con il valore maggiore tra i due parametri.
	/// \param fParam1 Valore 1.
	/// \param fParam2 Valore 2.
	AE_FORCEINLINE void SetMax( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 );

	/// \brief
	/// Imposta se stesso con il valore minore tra i due parametri.
	/// \param fParam1 Valore 1.
	/// \param fParam2 Valore 2.
	AE_FORCEINLINE void SetMin(  AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 );

	/// \brief
	/// Imposta se stesso con il valore del parametro \a fParam1 compreso tra \a fMinVal e \a fMaxVal.<BR>
	/// <tt>( this = min( fMaxVal, max(fParam1, fMinVal) ) )</tt>
	/// \param fParam1 Valore da impostare.
	/// \param fMinVal Valore minimo che pu&ograve; assumere \a fParam1.
	/// \param fMaxVal Valore massimo che pu&ograve; assumere \a fParam2.
	AE_FORCEINLINE void SetClamped( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fMinVal, AESimdFloat32ConstRef fMaxVal );

	/// \brief
	/// Imposta se stesso con il valore assoluto di fParam.
	/// <tt>( this = abs(fParam) )</tt>
	/// \param fParam1 Valore da impostare sul quale effettuare l'abs.
	AE_FORCEINLINE void SetAbs(  AESimdFloat32ConstRef fParam );

	/// \brief
	/// Imposta se stesso con il floor di \a fParam.
	/// <tt>( this = floor(fParam) )</tt>
	/// \param fParam1 Valore da impostare sul quale effettuare il floor.
	AE_FORCEINLINE void SetFloor(  AESimdFloat32ConstRef fParam );

	/// \brief
	/// Imposta se stesso con il resto della divisione tra \a fParam1 e \a fParam2<BR>
	/// <tt>( this = fmod(fParam1,fParam2) )</tt>
	/// \param fParam1 Dividendo.
	/// \param fParam2 Divisore.
	AE_FORCEINLINE void SetMod(  AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 );

	/// \brief
	/// Imposta se stesso con la somma dei valori di \a fParam1 e \a fParam2<BR>
	/// <tt>( this = fParam1+fParam2 )</tt>
	/// \param fParam1 Valore 1.
	/// \param fParam2 Valore 2.
	AE_FORCEINLINE void SetAdd( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 );

	/// \brief
	/// Imposta se stesso con la differenza tra i valori di \a fParam1 e \a fParam2<BR>
	/// <tt>( this = fParam1-fParam2 )</tt>
	/// \param fParam1 Valore 1.
	/// \param fParam2 Valore 2.
	AE_FORCEINLINE void SetSub( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 );

	/// \brief
	/// Imposta se stesso con il prodotto tra i valori di \a fParam1 e \a fParam2<BR>
	/// <tt>( this = fParam1*fParam2 )</tt>
	/// \param fParam1 Valore 1.
	/// \param fParam2 Valore 2.
	AE_FORCEINLINE void SetMul( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 );

	/// \brief
	/// Imposta se stesso con il quoziente tra i valori di \a fParam1 e \a fParam2<BR>
	/// <tt>( this = fParam1/fParam2 )</tt>
	/// \param fParam1 Valore 1.
	/// \param fParam2 Valore 2.
	/// \remark Precisione di default: 23bit. Divisione per 0 non controllata.
	AE_FORCEINLINE void SetDiv( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 );

	/// \brief
	/// Imposta se stesso sommando a \a fParam1 il prodotto tra i valori di \a fParam2 e \a fParam3<BR>
	/// <tt>( this = fParam1 + fParam2*fParam3 )</tt>
	/// \param fParam1 Valore 1.
	/// \param fParam2 Valore 2.
	/// \param fParam3 Valore 3.
	AE_FORCEINLINE void SetAddMul( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2, AESimdFloat32ConstRef fParam3 );

	/// \brief
	/// Imposta se stesso sottraendo a \a fParam1 il prodotto tra i valori di \a fParam2 e \a fParam3<BR>
	/// <tt>( this = fParam1 - fParam2*fParam3 )</tt>
	/// \param fParam1 Valore 1.
	/// \param fParam2 Valore 2.
	/// \param fParam3 Valore 3.
	AE_FORCEINLINE void SetSubMul( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2, AESimdFloat32ConstRef fParam3 );

	/// \brief
	/// Copia il valore di \a fParam cambiando segno se il valore in \a fSign &egrave; negativo.<BR>
	/// <tt>( this = ( fSign < 0 ) ? -fParam : fParam )</tt>
	/// \param fParam Valore di partenza.
	/// \param fSign Valore dal quale prende il segno.
	AE_FORCEINLINE void SetFlipSign( AESimdFloat32ConstRef fParam, AESimdFloat32ConstRef fSign );

	/// \brief
	/// Copia il valore di \a fParam cambiando segno se la maschera di bit &egrave; valorizzata.<BR>
	/// <tt>( this = ( vcMask ) ? -fParam : fParam )</tt>
	/// \param fParam Valore di partenza.
	/// \param vcMask Maschera di bit dalla quale prende il segno.
	/// \remark Tutti i bit della maschera \a vcComp devono essere impostati. Non sono ammesse
	/// maschere parziali.
	AE_FORCEINLINE void SetFlipSign( AESimdFloat32ConstRef fParam, AEVector4fConstRefCompParam vcMask );
	
	/// \brief
	/// Imposta se stesso con i valori di \a fTrueValue oppure \a fFalseValue in base alla maschera \a vcComp.<BR>
	/// <tt>( this = vcComp ? fTrueValue : fFalseValue )</tt>
	/// \remark Tutti i bit della maschera \a vcComp devono essere impostati. Non sono ammesse
	AE_FORCEINLINE void SetSelect( AEVector4fConstRefCompParam vcComp, AESimdFloat32ConstRef fTrueValue, AESimdFloat32ConstRef fFalseValue  );

	/// \brief
	/// Imposta \c this a 0 se la maschera di bit non &egrave; valorizzata.<BR>
	/// <tt>( this = ( vcCompareMask ) ? this : 0 )</tt>
	/// \param vcCompareMask Maschera di bit con la quale eseguire il confronto.
	AE_FORCEINLINE void ZeroIfFalse( AEVector4fConstRefCompParam vcCompareMask );

	/// \brief
	/// Imposta \c this a 0 se la maschera di bit &egrave; valorizzata.<BR>
	/// <tt>( this = ( vcCompareMask ) ? 0 : this )</tt>
	/// \param vcCompareMask Maschera di bit con la quale eseguire il confronto.
	AE_FORCEINLINE void ZeroIfTrue( AEVector4fConstRefCompParam vcCompareMask );

	///////////////////////////////////////////////////////////////
	/// @}
	/// @name Operazioni di Store e Load da e verso un indirizzo
	/// @{
	///////////////////////////////////////////////////////////////
	
	/// \brief
	/// Salva il valore floating point di \c this nell'indirizzo lpAddr.
	/// Il puntatore lpAddr deve essere allineato con la grandezza di AEDOUBLE64.
	/// \param Puntatore ad un indirizzo AEDOUBULE64.
	template <int N> AE_FORCEINLINE void Store( AEDOUBLE64 *lpAddr ) const;

	/// \brief
	/// Salva il valore floating point di \c this nell'indirizzo lpAddr.
	/// Il puntatore lpAddr deve essere allineato con la grandezza di AEFLOAT32.
	/// \param Puntatore ad un indirizzo AEFLOAT32.
	template <int N> AE_FORCEINLINE void Store( AEFLOAT32 *lpAddr ) const;

	/// \brief
	/// Carica in \c this il valore floating point puntato all'indirizzo lpAddr.
	/// Il puntatore lpAddr deve essere allineato con la grandezza di AEDOUBLE64.
	/// \param Puntatore ad un indirizzo AEDOUBULE64.
	template <int N> AE_FORCEINLINE void Load( const AEDOUBLE64 *lpAddr );

	/// \brief
	/// Carica in \c this il valore floating point puntato all'indirizzo lpAddr.
	/// Il puntatore lpAddr deve essere allineato con la grandezza di AEFLOAT32.
	/// \param Puntatore ad un indirizzo AEFLOAT32.
	template <int N> AE_FORCEINLINE void Load( const AEFLOAT32 *lpAddr );

	///////////////////////////////////////////////////////////////
	/// @}
	/// @name Operatori
	/// @{
	///////////////////////////////////////////////////////////////

	/// \brief
	/// Converte se stesso in un valore floating point e lo ritorna.
	AE_FORCEINLINE operator AEFLOAT32( void ) const;

	/// \brief
	/// Copia in \c this il contenuto di \a fValue.
	/// \param nValue Valore da copiare.
	AE_FORCEINLINE void operator= ( AESimdFloat32ConstRef fValue );

	/// \brief
	/// Operatore di negazione valore. 
	/// \return \c -this
	AE_FORCEINLINE const AESimdFloat32 operator-( void ) const;

	/// \brief
	/// Esegue la somma del valore di \c this con il valore di \a fParam.
	/// \param fParam Valore da sommare.
	/// \return <tt>this + fParam</tt>
	AE_FORCEINLINE const AESimdFloat32 operator+ ( AESimdFloat32ConstRef fParam ) const;

	/// \brief
	/// Esegue la differenza tra il valori di \c this e il valore di \a fParam.
	/// \param fParam Valore da sottrarre
	/// \return <tt>this - fParam</tt>
	AE_FORCEINLINE const AESimdFloat32 operator- ( AESimdFloat32ConstRef fParam ) const;

	/// \brief
	/// Calcola il prodotto tra il valore di \c this e il valore di \a fParam.
	/// \param fParam Valore da moltiplicare
	/// \return <tt>this * fParam</tt>
	AE_FORCEINLINE const AESimdFloat32 operator* ( AESimdFloat32ConstRef fParam ) const;

	/// \brief
	/// Ritorna il quoziente tra il valore di \c this e il valore di \a fParam. La divisione per 0
	/// non &egrave; controllata.
	/// \param fParam Valore da dividere
	/// \return <tt>this / fParam</tt>
	AE_FORCEINLINE const AESimdFloat32 operator/ ( AESimdFloat32ConstRef fParam ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; minore di \a fValue.
	/// \param fParam Valore da confrontare.
	/// \return <tt>(this < fParam)</tt>	
	AE_FORCEINLINE AEBOOL32 operator< ( AESimdFloat32ConstRef fValue ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; minore o uguale a \a fValue.
	/// \param fParam Valore da confrontare.
	/// \return <tt>(this <= fParam)</tt>	
	AE_FORCEINLINE AEBOOL32 operator<= ( AESimdFloat32ConstRef fValue ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; maggiore di \a fValue.
	/// \param fParam Valore da confrontare.
	/// \return <tt>(this > fParam)</tt>	
	AE_FORCEINLINE AEBOOL32 operator> ( AESimdFloat32ConstRef fValue ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; maggiore o uguale a \a fValue.
	/// \param fParam Valore da confrontare.
	/// \return <tt>(this >= fParam)</tt>	
	AE_FORCEINLINE AEBOOL32 operator>= ( AESimdFloat32ConstRef fValue ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; uguale a \a fValue.
	/// \param fParam Valore da confrontare.
	/// \return <tt>(this == fParam)</tt>	
	AE_FORCEINLINE AEBOOL32 operator== ( AESimdFloat32ConstRef fValue ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; diverso da \a fValue.
	/// \param fParam Valore da confrontare.
	/// \return <tt>(this != fParam)</tt>	
	AE_FORCEINLINE AEBOOL32 operator!= ( AESimdFloat32ConstRef fValue ) const;

	///////////////////////////////////////////////////////////////
	/// @}
	/// @name Operazioni aritmetiche
	/// @{
	///////////////////////////////////////////////////////////////
	
	/// \brief
	/// Addiziona a \c this il valore di \a fParam.
	/// \param fParam Valore da addizionare
	AE_FORCEINLINE void Add( AESimdFloat32ConstRef fParam );

	/// \brief
	/// Sottrae a \c this il valore di \a fParam.
	/// \param fParam Valore da sottrarre
	AE_FORCEINLINE void Sub( AESimdFloat32ConstRef fParam );

	/// \brief
	/// Moltiplica \c this con il valore di \a fParam.
	/// \param fParam Valore da moltiplicare
	AE_FORCEINLINE void Mul( AESimdFloat32ConstRef fParam );

	/// \brief
	/// Divide \c this con il valore di \a fParam.<BR>
	/// \param fParam Valore da dividere
	/// \remark Precisione di default: 23 bit, Divisione per 0 non controllata.
	AE_FORCEINLINE void Div( AESimdFloat32ConstRef fParam );

	/// \brief
	/// Addiziona a \c this il risultato del prodotto tra \a fParam1 e \a fParam2.<BR>
	/// <tt>this += fParam1*fParam2</tt>
	/// \param fParam1 Valore 1
	/// \param fParam2 Valore 2
	AE_FORCEINLINE void AddMul( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 );

	/// \brief
	/// Sottrae a \c this il risultato del prodotto tra \a fParam1 e \a fParam2.<BR>
	/// <tt>this -= fParam1*fParam2</tt>
	/// \param fParam1 Valore 1
	/// \param fParam2 Valore 2
	AE_FORCEINLINE void SubMul( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 );

	///////////////////////////////////////////////////////////////
	/// @}
	/// @name Operazioni avanzate
	/// @{
	///////////////////////////////////////////////////////////////
	
	/// \brief
	/// Calcola la radice quadrata del valore di \c this.
	/// \return <tt>sqrtf( this )</tt>
	/// \remark Precisione di default: 23 bit. I valori negativi vengono impostati a 0.
	AE_FORCEINLINE const AESimdFloat32 Sqrt( void ) const;

	/// \brief
	/// Calcola la radice quadrata inversa del valore di \c this.
	/// \return <tt>1/sqrtf( this )</tt>
	/// \remark Precisione di default: 23 bit. I valori negativi vengono impostati a 0.<BR>
	/// La divisione per 0 &egrave; controllata impostando eventualmente il risultato a 0.
	AE_FORCEINLINE const AESimdFloat32 SqrtInverse( void ) const;

	/// \brief
	/// Imposta se stesso con il reciproco del valore di \a fValue.<BR>
	/// <tt>this = 1/fValue</tt>
	/// \remark Precisione di default: 23 bit. La divisione per 0 non &egrave; controllata.
	AE_FORCEINLINE void SetReciprocal( AESimdFloat32ConstRef fValue );

	/// \brief
	/// Ritorna il reciproco di se stesso.
	/// \return <tt>1/this</tt>
	/// \remark Precisione di default: 23 bit. La divisione per 0 non &egrave; controllata.
	AE_FORCEINLINE const AESimdFloat32 Reciprocal( void ) const;

	template <int N> 
	AE_FORCEINLINE void SetDot( AEVector4fRefParam fParam1, AEVector4fRefParam fParam2 );

	/// Sets self to a linear interpolation of the values \a a and \a b.
	/// The parameter \a t specifies the relative position between
	/// \a a and \a b.  With \a t = 0, the value \a a will be returned.
	/// ( self = (1-t)*a + t*b )
	AE_FORCEINLINE void SetInterpolate( AESimdFloat32ConstRef a, AESimdFloat32ConstRef b, AESimdFloat32ConstRef t  );

	///////////////////////////////////////////////////////////////
	/// @}
	/// @name Operazioni di controllo
	/// @{
	///////////////////////////////////////////////////////////////
	
	/// Sign test whether negative sign is set, in which case true is returned. ( return self <= -0 ).
	/// This includes detecting floating point -0.0 which also returns true. Use the isEqual... methods 
	/// or the overloaded comparison operators to perform arithmetic compares on the value.
	AE_FORCEINLINE AEBOOL32 IsSignBitSet( void ) const;

	/// Sign test whether negative sign is clear, in which case true is returned. ( return self >= +0 ).
	/// This includes detecting floating point +0.0 which also returns true. Use the isEqual... methods 
	/// or the overloaded comparison operators to perform arithmetic compares on the value.
	AE_FORCEINLINE AEBOOL32 IsSignBitClear( void ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; minore del valore di \a fValue.
	/// \return <tt>this < fValue</tt>
	AE_FORCEINLINE AEBOOL32 IsLess( AESimdFloat32ConstRef fValue ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; minore o uguale al valore di \a fValue.
	/// \return <tt>this <= fValue</tt>
	AE_FORCEINLINE AEBOOL32 IsLessEqual( AESimdFloat32ConstRef fValue ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; maggiore del valore di \a fValue.
	/// \return <tt>this > fValue</tt>
	AE_FORCEINLINE AEBOOL32 IsGreater( AESimdFloat32ConstRef fValue ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; maggiore o uguale al valore di \a fValue.
	/// \return <tt>this >= fValue</tt>
	AE_FORCEINLINE AEBOOL32 IsGreaterEqual( AESimdFloat32ConstRef fValue ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; uguale al valore di \a fValue.
	/// \return <tt>this == fValue</tt>
	AE_FORCEINLINE AEBOOL32 IsEqual( AESimdFloat32ConstRef fValue ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; diverso dal valore di \a fValue.
	/// \return <tt>this != fValue</tt>
	AE_FORCEINLINE AEBOOL32 IsNotEqual( AESimdFloat32ConstRef fValue ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; minore di 0.
	/// \return <tt>this < 0</tt>
	AE_FORCEINLINE AEBOOL32 IsLessZero( void ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; minore o uguale a 0.
	/// \return <tt>this <= 0</tt>
	AE_FORCEINLINE AEBOOL32 IsLessEqualZero( void ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; maggiore di 0.
	/// \return <tt>this > 0</tt>
	AE_FORCEINLINE AEBOOL32 IsGreaterZero( void ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; maggiore o uguale a 0.
	/// \return <tt>this >= 0</tt>
	AE_FORCEINLINE AEBOOL32 IsGreaterEqualZero( void ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; uguale a 0.
	/// \return <tt>this == 0</tt>
	AE_FORCEINLINE AEBOOL32 IsEqualZero( void ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; diverso da 0.
	/// \return <tt>this != 0</tt>
	AE_FORCEINLINE AEBOOL32 IsNotEqualZero( void ) const;

	/// \brief
	/// Ritorna TRUE se il valore di \c this &egrave; un numero floating point valido.
	/// \return <tt>this != NaN && this != +INF && this != -INF</tt>
	AE_FORCEINLINE AEBOOL32 IsOk( void ) const;

	/// Sign test whether negative sign is set, in which case the mask returned is true. ( self <= -0 ).
	/// This includes detecting floating point -0.0 which also returns true. Use the compare methods 
	/// or the overloaded comparison operators to perform arithmetic compares on the value.
	AE_FORCEINLINE const AEVector4fComparison SignBitSet( void ) const;

	/// Sign test whether negative sign is clear, in which case the mask returned is true. ( self >= +0 ).
	/// This includes detecting floating point +0.0 which also returns true. Use the compare methods 
	/// or the overloaded comparison operators to perform arithmetic compares on the value.
	AE_FORCEINLINE const AEVector4fComparison SignBitClear( void ) const;

	///////////////////////////////////////////////////////////////
	/// @}
	/// @name Operazioni di comparazione
	/// @{
	///////////////////////////////////////////////////////////////
	
	/// Compare the value of self less than the value of \a a. ( self < a )
	AE_FORCEINLINE const AEVector4fComparison CmpL( AESimdFloat32ConstRef fValue ) const;

	/// Compare the value of self less than or equal the value of \a a. ( self <= a )
	AE_FORCEINLINE const AEVector4fComparison CmpLE( AESimdFloat32ConstRef fValue ) const;

	/// Compare the value of self greater than the value of \a a. ( self > a )
	AE_FORCEINLINE const AEVector4fComparison CmpG( AESimdFloat32ConstRef fValue ) const;

	/// Compare the value of self greater than or equal the value of \a a. ( self >= a )
	AE_FORCEINLINE const AEVector4fComparison CmpGE( AESimdFloat32ConstRef fValue ) const;

	/// Compare the value of self equal to the value of \a a. ( self == a )
	AE_FORCEINLINE const AEVector4fComparison CmpE( AESimdFloat32ConstRef fValue ) const;

	/// Compare the value of self not equal to the value of \a a. ( self != a )
	AE_FORCEINLINE const AEVector4fComparison CmpNE( AESimdFloat32ConstRef fValue ) const;

	/// Compare the value of self less than zero. ( self < 0 )
	AE_FORCEINLINE const AEVector4fComparison CmpLessZero( void ) const;

	/// Compare the value of self less than or equal zero. ( self <= 0 )
	AE_FORCEINLINE const AEVector4fComparison CmpLessEqualZero( void ) const;

	/// Compare the value of self greater than zero. ( self > 0 )
	AE_FORCEINLINE const AEVector4fComparison CmpGreaterZero( void ) const;

	/// Compare the value of self greater than or equal zero. ( self >= 0 )
	AE_FORCEINLINE const AEVector4fComparison CmpGreaterEqualZero( void ) const;

	/// Compare the value of self equal to zero. ( self == 0 )
	AE_FORCEINLINE const AEVector4fComparison CmpEqualZero( void ) const;

	/// Compare the value of self not equal to zero. ( self != 0 )
	AE_FORCEINLINE const AEVector4fComparison CmpNotEqualZero( void ) const;

	/// Compares self to \a v and returns true if the difference is within \a epsilon range (exclusive). ( self > v-epsilon && self < v+epsilon )
	AE_FORCEINLINE AEBOOL32 ApproxEqual( AESimdFloat32ConstRef fValue, AESimdFloat32ConstRef fEpsilon ) const;

	///////////////////////////////////////////////////////////////
	/// @}
	/// @name Interfaccia avanzata.
	/// @{
	///////////////////////////////////////////////////////////////
	
	/// Load a double precision floating point value from address \a p.
	/// See the documentation at the template values for the requested behavior.
	/// \remark Template parameter N needs to be 1. It is there for compatibility with hkVector4f.
	template <int N, AEMathIoMode A> AE_FORCEINLINE void Load( const AEDOUBLE64 *lpAddr );

	/// Load a single precision floating point value from address \a p.
	/// See the documentation at the template values for the requested behavior.
	/// \remark Template parameter N needs to be 1. It is there for compatibility with hkVector4f.
	template <int N, AEMathIoMode A> AE_FORCEINLINE void Load( const AEFLOAT32 *lpAddr );

	/// Store the floating point value of self to address \a p as a double precision value.
	/// The rounding is the system default.
	/// See the documentation at the template values for the requested behavior.
	/// \remark Template parameter N needs to be 1. It is there for compatibility with hkVector4f.
	template <int N, AEMathIoMode A> AE_FORCEINLINE void Store( AEDOUBLE64 *lpAddr ) const;

	/// Store the floating point value of self to address \a p as a single precision value.
	/// The rounding is the system default.
	/// See the documentation at the template values for the requested behavior.
	/// \remark Template parameter N needs to be 1. It is there for compatibility with hkVector4f.
	template <int N, AEMathIoMode A> AE_FORCEINLINE void Store( AEFLOAT32 *lpAddr ) const;

	/// Store the floating point value of self to address \a p as a double precision value.
	/// See the documentation at the template values for the requested behavior.
	/// \remark Template parameter N needs to be 1. It is there for compatibility with hkVector4f.
	template <int N, AEMathIoMode A, AEMathRoundingMode R> AE_FORCEINLINE void Store( AEDOUBLE64 *lpAddr ) const;

	/// Store the floating point value of self to address \a p as a single precision value.
	/// See the documentation at the template values for the requested behavior.
	/// \remark Template parameter N needs to be 1. It is there for compatibility with hkVector4f.
	template <int N, AEMathIoMode A, AEMathRoundingMode R> AE_FORCEINLINE void Store( AEFLOAT32 *lpAddr ) const;

	/// Set self to the reciprocal value of \a a. ( self = 1/a ).
	/// See the documentation at the template values for the requested behavior.
	template <AEMathAccuracyMode A, AEMathDivByZeroMode D> AE_FORCEINLINE void SetReciprocal( AESimdFloat32ConstRef fValue );

	/// Set self to the quotient of \a a over \a b. ( self = a/b ).
	/// See the documentation at the template values for the requested behavior.
	template <AEMathAccuracyMode A, AEMathDivByZeroMode D> AE_FORCEINLINE void SetDiv( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 );

	/// Divide self by the value of \a a. ( self /= a ).
	/// See the documentation at the template values for the requested behavior.
	template <AEMathAccuracyMode A, AEMathDivByZeroMode D> AE_FORCEINLINE void Div( AESimdFloat32ConstRef fParam );

	/// Return the square root value of self. ( return sqrt(self) ).
	/// See the documentation at the template values for the requested behavior.
	template <AEMathAccuracyMode A, AEMathNegSqrtMode S> AE_FORCEINLINE const AESimdFloat32 Sqrt( void ) const;

	/// Return the inverse square root of self. ( return 1/sqrt(self) ).
	/// See the documentation at the template values for the requested behavior.
	template <AEMathAccuracyMode A, AEMathNegSqrtMode S> AE_FORCEINLINE const AESimdFloat32 SqrtInverse( void ) const;

	/// @}
};

#endif //_AESIMDFLOAT32_H_
